#ifndef TAB_H
#define TAB_H
#include <vector>
using namespace std;

// Class Tab - generic for dynamic 2D tables of elements
// Interface template class Tab
// Warning: will not compile for T = bool (because of vector<bool> spacialization)

template<class T> class table {
	
private:
	vector<vector<T> > t;   // container
	// number of rows = t.size()
	int c;                  // number of columns

public:
	class Tab_err {};       // type for reporting errors
	table();                // create an empty table
	table(int);             // create a nxn table
	table(int, int);        // create a nxm table
	table(const table<T>&); // copy constructor
	T& operator()(int, int);  //return (ref to) elem t[i][j]
	T& at(int, int);          //return (ref to) elem t[i][j]
	int rows() const;         //return number of rows in table
	int cols() const;         //return number of columns in table
	void push_back_row(const vector<T>&);   //add a row
	void push_back_col(const vector<T>&);   //add a column
	void resize_rows(int);      //change the number of rows
	void resize_cols(int);      //change the number of columms
	void resize(int, int);      //change size of the table
};    // end interface template class Tab

// Implementation template class Tab
// explicit default constructor is needed to reset c;
// t is automtically set to an empty vector
template <class T> table<T>::table() : c(0) {}

template <class T> table<T>::table(int n) : c(n) { // c=n
	t.resize(n);
	for (int i=0; i<n; i++) t[i].resize(c);
}

template <class T> table<T>::table(int n, int m) : c(m) {
	t.resize(n);
	for (int i=0; i<n; i++) t[i].resize(c);
}

template <class T> table<T>::table(const table<T>& t1) : t(t1.t), c(t1.c) {}

template <class T> T& table<T>::operator()(int rr, int cc) {
	return t[rr][cc];
}

template <class T> T& table<T>::at(int i, int j) {
	return t[i][j];
}

template <class T> int table<T>::rows() const {
	return t.size();
}

template <class T> int table<T>::cols() const {
	return c;
}

template <class T> void table<T>::push_back_row(const vector<T>& v) {
	if (v.size()<c) throw Tab_err();  // error - new row too short
	t.push_back(v);
	t[t.size()-1].resize(c);    // make sure new row has the same number of cols
}

template <class T> void table<T>::push_back_col(const vector<T>& v) {
	if (v.size()<t.size()) throw Tab_err();  // error - new column too short
	c++;
	for (int i=0; i<t.size(); i++) {
		t[i].resize(c);
		t[i][c-1]=v[i];
	}
}

template <class T> void table<T>::resize_rows(int n) {
	int rr = t.size();
	t.resize(n);
	for (int i=rr; i<n; i++) t[i].resize(c);
}

template <class T> void table<T>::resize_cols(int m) {
	c = m;
	for (int i=0; i<t.size(); i++) t[i].resize(c);
}

template <class T> void table<T>::resize(int n, int m) {
	c = m;
	t.resize(n);
	for (int i=0; i<n; i++) t[i].resize(c);
}

// end implementation template class Tab

#endif // TAB_H
